package cn.b504.qpcr.utils;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;

/**
 * @author ssc
 * @apiNote update: 2020-06-08 21:20
 * @apiNote update: 2020-04-21 20:00
 */
public class ExcelUtils {
  /**
   * 获取表头的 XSSFCellStyle 对象，即 Arial 字体、加粗、水平垂直居中的 XSSFCellStyle 对象
   *
   * @param workbook 要应用的 XSSFWorkbook 对象
   * @return 可被 setCellStyle 设置的 XSSFCellStyle 对象
   */
  private static XSSFCellStyle getHeadStyle(XSSFWorkbook workbook) {
    XSSFFont headFont = workbook.createFont();
    headFont.setBold(true);
    headFont.setFontName("Arial");
    return getCellStyle_CenterInParent(workbook, headFont);
  }

  /**
   * 获取表格主体的 XSSFCellStyle 对象，即 Arial 字体、加粗、水平垂直居中的 XSSFCellStyle 对象
   *
   * @param workbook 要应用的 XSSFWorkbook 对象
   * @return 可被 setCellStyle 设置的 XSSFCellStyle 对象
   */
  private static XSSFCellStyle getBodyStyle(XSSFWorkbook workbook) {
    XSSFFont bodyFont = workbook.createFont();
    bodyFont.setFontName("Arial");
    return getCellStyle_CenterInParent(workbook, bodyFont);
  }

  /**
   * 获取水平垂直居中的 XSSFCellStyle 对象
   *
   * @param workbook 要应用的 XSSFWorkbook 对象
   * @param font     要应用的字体
   * @return 可被 setCellStyle 设置的 XSSFCellStyle 对象
   */
  private static XSSFCellStyle getCellStyle_CenterInParent(XSSFWorkbook workbook, XSSFFont font) {
    XSSFCellStyle cellStyle = workbook.createCellStyle();
    cellStyle.setAlignment(HorizontalAlignment.CENTER);
    cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    cellStyle.setFont(font);
    return cellStyle;
  }

  private static void autoSizeColumn(XSSFSheet sheet, int colNum) {
    for (int i = 0; i < colNum; i++) {
      sheet.autoSizeColumn(i);
    }
  }

  /**
   * 往 sheet 上加一个二维数组，使用表头格式
   *
   * @param dataList 二维数组，数据内容
   * @param sheet    要添加内容的目标 sheet
   */
  public static void addHeadData2Sheet(List<List<String>> dataList, XSSFSheet sheet) {
    addHeadData2Sheet(dataList, sheet, true);
  }

  /**
   * 往 sheet 上加一个二维数组，使用表头格式
   *
   * @param dataList       二维数组，数据内容
   * @param sheet          要添加内容的目标 sheet
   * @param autoSizeColumn 使列宽度自适应内容
   */
  public static void addHeadData2Sheet(List<List<String>> dataList, XSSFSheet sheet, boolean autoSizeColumn) {
    XSSFCellStyle headStyle = getHeadStyle(sheet.getWorkbook());
    addData2Sheet(dataList, headStyle, sheet, autoSizeColumn);
  }

  /**
   * 往 sheet 上加一个二维数组，使用表内容格式
   *
   * @param dataList 二维数组，数据内容
   * @param sheet    要添加内容的目标 sheet
   */
  public static void addBodyData2Sheet(List<List<String>> dataList, XSSFSheet sheet) {
    addBodyData2Sheet(dataList, sheet, true);
  }

  /**
   * 往 sheet 上加一个二维数组，使用表内容格式
   *
   * @param dataList       二维数组，数据内容
   * @param sheet          要添加内容的目标 sheet
   * @param autoSizeColumn 使列宽度自适应内容
   */
  public static void addBodyData2Sheet(List<List<String>> dataList, XSSFSheet sheet, boolean autoSizeColumn) {
    XSSFCellStyle bodyStyle = getBodyStyle(sheet.getWorkbook());
    addData2Sheet(dataList, bodyStyle, sheet, autoSizeColumn);
  }

  private static void addData2Sheet(List<List<String>> dataList, XSSFCellStyle cellStyle, XSSFSheet sheet, boolean autoSizeColumn) {
    dataList.forEach(list -> {
      XSSFRow row = sheet.createRow(sheet.getLastRowNum() + 1);
      list.forEach(it -> {
        XSSFCell cell = row.createCell(Math.max(row.getLastCellNum(), 0));
        cell.setCellStyle(cellStyle);
        if (it.length() == 0) {
          return;
        }
        switch (it.toLowerCase(Locale.ROOT)) {
          case "true":
            cell.setCellValue(true);
            break;
          case "false":
            cell.setCellValue(false);
            break;
          default:
            if (MathUtils.isDoubleNumber(it)) {
              cell.setCellValue(Double.parseDouble(it));
            } else {
              cell.setCellValue(it);
            }
            break;
        }
      });
    });

    if (autoSizeColumn && dataList.size() > 0) {
      Num num = new Num();
      dataList.forEach(it -> num.n = Math.max(num.n, it.size()));
      autoSizeColumn(sheet, (int) num.n);
    }
  }


  /**
   * 通过 File 对象读取到 XSSFWorkbook 对象
   *
   * @param file Excel 表格 file
   * @return 读取到的 XSSFWorkbook 对象
   * @throws IOException InputStream 异常
   */
  public static XSSFWorkbook getWorkbook(File file) throws IOException {
    FileInputStream fileInputStream = new FileInputStream(file);
    XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
    workbook.setMissingCellPolicy(Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
    fileInputStream.close();
    return workbook;
  }

  /**
   * 根据 Cell 的类型返回 Cell 的值
   *
   * @param cell 要读取的 Cell
   * @return Cell 的值
   */
  public static String getCellValue(Cell cell) {
    String str = "";
    switch (cell.getCellType()) {
      case NUMERIC:
        str = String.valueOf(cell.getNumericCellValue());
        break;
      case STRING:
        str = cell.getStringCellValue();
        break;
      case BOOLEAN:
        str = String.valueOf(cell.getBooleanCellValue());
        break;
    }
    return str;
  }
}
